using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;

namespace bkfviewer {
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public class MTF_DB_HDR {
        [Category("DBLK Header"), Browsable(false)]
        public uint DBLKType { get { return BitConverter.ToUInt32(bin, 0); } }
        [Category("DBLK Header"), Browsable(false)]
        public uint BlockAttributes { get { return BitConverter.ToUInt32(bin, 4); } }
        [Category("DBLK Header")]
        public ushort OffsetToFirstEvent { get { return BitConverter.ToUInt16(bin, 8); } }
        [Category("DBLK Header")]
        public byte OSID { get { return bin[10]; } }
        [Category("DBLK Header")]
        public byte OSVersion { get { return bin[11]; } }
        [Category("DBLK Header")]
        public ulong DisplayableSize { get { return BitConverter.ToUInt64(bin, 12); } }
        [Category("DBLK Header")]
        public ulong FormatLogicalAddress { get { return BitConverter.ToUInt64(bin, 20); } }
        [Category("DBLK Header")]
        public ushort ReservedforMBC { get { return BitConverter.ToUInt16(bin, 28); } }
        [Category("DBLK Header")]
        public uint ControlBlockID { get { return BitConverter.ToUInt32(bin, 36); } }
        [Category("DBLK Header")]
        public MTF_TAPE_ADDRESS OSSpecificData { get { return new MTF_TAPE_ADDRESS(bin, 44); } }
        [Category("DBLK Header")]
        public byte StringType { get { return bin[48]; } }
        [Category("DBLK Header")]
        public ushort HeaderChecksum { get { return BitConverter.ToUInt16(bin, 50); } }

        [Category("DBLK Header"), Description("The DBLK Type field identifies the type of DBLK (MTF_SSET, MTF_VOLB, etc.).")]
        public string DBLKName { get { return Encoding.ASCII.GetString(bin, 0, 4); } }

        // DBLK Type: any
        [Category("BlockAttributes")]
        public bool MTF_CONTINUATION { get { return 0 != (BlockAttributes & 0x00000001U); } }
        [Category("BlockAttributes")]
        public bool MTF_COMPRESSION { get { return 0 != (BlockAttributes & 0x00000004U); } }
        [Category("BlockAttributes")]
        public bool MTF_EOS_AT_EOM { get { return 0 != (BlockAttributes & 0x00000008U); } }

        /*
        // DBLK Type: MTF_ESET
        [Category("MTF_ESET")]
        public bool MTF_FDD_ABORTED { get { return 0 != (BlockAttributes & 0x00010000U); } }
        [Category("MTF_ESET")]
        public bool MTF_END_OF_FAMILY { get { return 0 != (BlockAttributes & 0x00020000U); } }
        [Category("MTF_ESET")]
        public bool MTF_ABORTED_SET { get { return 0 != (BlockAttributes & 0x00040000U); } }

        // DBLK Type: MTF_EOTM
        [Category("MTF_EOTM")]
        public bool MTF_NO_ESET_PBA { get { return 0 != (BlockAttributes & 0x00010000U); } }
        [Category("MTF_EOTM")]
        public bool MTF_INVALID_ESET_PBA { get { return 0 != (BlockAttributes & 0x00020000U); } }
         * */

        [Category("StringType")]
        public bool NO_STRINGS { get { return StringType == 0; } }
        [Category("StringType")]
        public bool ANSI_STR { get { return StringType == 1; } }
        [Category("StringType")]
        public bool UNICODE_STR { get { return StringType == 2; } }

        byte[] bin;

        public MTF_DB_HDR(byte[] bin) {
            this.bin = bin;
        }
    }

    class Strut {
        public static string GetStr(byte[] bin, int off, MTF_TAPE_ADDRESS addr, byte strtype) {
            if (strtype == 2) {
                return Encoding.Unicode.GetString(bin, addr.Offset + off, addr.Size);
            }
            else {
                return Encoding.ASCII.GetString(bin, addr.Offset + off, addr.Size);
            }
        }
    }

    public class MTF_TAPE1 : MTF_DB_HDR {
        [Category("TAPE Header")]
        public uint MediaFamilyID { get { return BitConverter.ToUInt32(bin, 52); } }
        [Category("TAPE Header"), Browsable(false)]
        public uint TAPEAttributes { get { return BitConverter.ToUInt32(bin, 56); } }
        [Category("TAPE Header")]
        public ushort MediaSequenceNumber { get { return BitConverter.ToUInt16(bin, 60); } }
        [Category("TAPE Header")]
        public ushort PasswordEncryptionAlgorithm { get { return BitConverter.ToUInt16(bin, 62); } }
        [Category("TAPE Header")]
        public ushort SoftFilemarkBlockSize { get { return BitConverter.ToUInt16(bin, 64); } }
        [Category("TAPE Header")]
        public ushort MediaBasedCatalogType { get { return BitConverter.ToUInt16(bin, 66); } }
        [Category("TAPE Header")]
        public MTF_TAPE_ADDRESS MediaName { get { return new MTF_TAPE_ADDRESS(bin, 68); } }
        [Category("TAPE Header")]
        public MTF_TAPE_ADDRESS MediaDescription { get { return new MTF_TAPE_ADDRESS(bin, 72); } }
        [Category("TAPE Header")]
        public MTF_TAPE_ADDRESS MediaPassword { get { return new MTF_TAPE_ADDRESS(bin, 76); } }
        [Category("TAPE Header")]
        public MTF_TAPE_ADDRESS SoftwareName { get { return new MTF_TAPE_ADDRESS(bin, 80); } }
        [Category("TAPE Header")]
        public ushort FormatLogicalBlockSize { get { return BitConverter.ToUInt16(bin, 84); } }
        [Category("TAPE Header")]
        public ushort SoftwareVendorID { get { return BitConverter.ToUInt16(bin, 86); } }
        [Category("TAPE Header")]
        public MTF_DATE_TIME MediaDate { get { return new MTF_DATE_TIME(bin, 88); } }
        [Category("TAPE Header")]
        public byte MTFMajorVersion { get { return bin[93]; } }

        [Category("TAPE Header")]
        public string MediaNameText { get { return Strut.GetStr(bin, 0, MediaName, this.StringType); } }
        [Category("TAPE Header")]
        public string MediaDescriptionText { get { return Strut.GetStr(bin, 0, MediaDescription, this.StringType); } }
        [Category("TAPE Header")]
        public string MediaPasswordText { get { return Strut.GetStr(bin, 0, MediaPassword, this.StringType); } }
        [Category("TAPE Header")]
        public string SoftwareNameText { get { return Strut.GetStr(bin, 0, SoftwareName, this.StringType); } }

        // DBLK Type: MTF_TAPE
        [Category("BlockAttributes")]
        public bool MTF_SET_MAP_EXISTS { get { return 0 != (this.BlockAttributes & 0x00010000U); } }
        [Category("BlockAttributes")]
        public bool MTF_FDD_ALLOWED { get { return 0 != (this.BlockAttributes & 0x00020000U); } }

        byte[] bin;

        public MTF_TAPE1(byte[] bin)
            : base(bin) {
            this.bin = bin;
        }
    }

    public class MTF_SFMB1 : MTF_DB_HDR {
        [Category("SFMB Header")]
        public uint NumberofFilemarkEntries { get { return BitConverter.ToUInt32(bin, 52); } }
        [Category("SFMB Header")]
        public uint FilemarkEntriesUsed { get { return BitConverter.ToUInt32(bin, 56); } }
        [Category("SFMB Header")]
        public uint[] PBAofPreviousFilemarksArray {
            get {
                uint cx = FilemarkEntriesUsed;
                uint[] al = new uint[cx];
                for (uint x = 0; x < cx; x++) {
                    al[x] = BitConverter.ToUInt32(bin, Convert.ToInt32(60 + 4 * x));
                }
                return al;
            }
        }

        byte[] bin;

        public MTF_SFMB1(byte[] bin)
            : base(bin) {
            this.bin = bin;
        }
    }

    public class MTF_SSET1 : MTF_DB_HDR {
        [Category("SSET Header"), Browsable(false)]
        public uint SSETAttributes { get { return BitConverter.ToUInt32(bin, 52); } }
        [Category("SSET Header")]
        public ushort PasswordEncryptionAlgorithm { get { return BitConverter.ToUInt16(bin, 56); } }
        [Category("SSET Header")]
        public ushort SoftwareCompressionAlgorithm { get { return BitConverter.ToUInt16(bin, 58); } }
        [Category("SSET Header")]
        public ushort SoftwareVendorID { get { return BitConverter.ToUInt16(bin, 60); } }
        [Category("SSET Header")]
        public ushort DataSetNumber { get { return BitConverter.ToUInt16(bin, 62); } }
        [Category("SSET Header")]
        public MTF_TAPE_ADDRESS DataSetName { get { return new MTF_TAPE_ADDRESS(bin, 64); } }
        [Category("SSET Header")]
        public MTF_TAPE_ADDRESS DataSetDescription { get { return new MTF_TAPE_ADDRESS(bin, 68); } }
        [Category("SSET Header")]
        public MTF_TAPE_ADDRESS DataSetPassword { get { return new MTF_TAPE_ADDRESS(bin, 72); } }
        [Category("SSET Header")]
        public MTF_TAPE_ADDRESS UserName { get { return new MTF_TAPE_ADDRESS(bin, 76); } }
        [Category("SSET Header")]
        public ulong PhysicalBlockAddress { get { return BitConverter.ToUInt64(bin, 80); } }
        [Category("SSET Header")]
        public MTF_DATE_TIME MediaWriteDate { get { return new MTF_DATE_TIME(bin, 88); } }
        [Category("SSET Header")]
        public byte SoftwareMajorVersion { get { return bin[93]; } }
        [Category("SSET Header")]
        public byte SoftwareMinorVersion { get { return bin[94]; } }
        [Category("SSET Header")]
        public sbyte TimeZone { get { return (sbyte)bin[95]; } }
        [Category("SSET Header")]
        public byte MTFMinorVersion { get { return bin[96]; } }
        [Category("SSET Header")]
        public byte MediaCatalogVersion { get { return bin[97]; } }

        [Category("SSET Header")]
        public string DataSetNameText { get { return Strut.GetStr(bin, 0, DataSetName, this.StringType); } }
        [Category("SSET Header")]
        public string DataSetDescriptionText { get { return Strut.GetStr(bin, 0, DataSetDescription, this.StringType); } }
        [Category("SSET Header")]
        public string DataSetPasswordText { get { return Strut.GetStr(bin, 0, DataSetPassword, this.StringType); } }
        [Category("SSET Header")]
        public string UserNameText { get { return Strut.GetStr(bin, 0, UserName, this.StringType); } }

        [Category("SSETAttributes")]
        public bool SSET_TRANSFER_BIT { get { return 0 != (SSETAttributes & (1U << 0)); } }
        [Category("SSETAttributes")]
        public bool SSET_COPY_BIT { get { return 0 != (SSETAttributes & (1U << 1)); } }
        [Category("SSETAttributes")]
        public bool SSET_NORMAL_BIT { get { return 0 != (SSETAttributes & (1U << 2)); } }
        [Category("SSETAttributes")]
        public bool SSET_DIFFERENTIAL_BIT { get { return 0 != (SSETAttributes & (1U << 3)); } }
        [Category("SSETAttributes")]
        public bool SSET_INCREMENTAL_BIT { get { return 0 != (SSETAttributes & (1U << 4)); } }
        [Category("SSETAttributes")]
        public bool SSET_DAILY_BIT { get { return 0 != (SSETAttributes & (1U << 5)); } }

        [Category("TimeZone")]
        public bool LOCAL_TZ { get { return TimeZone == 127; } }

        // DBLK Type: MTF_SSET
        [Category("BlockAttributes")]
        public bool MTF_FDD_EXISTS { get { return 0 != (this.BlockAttributes & (1U << 16)); } }
        [Category("BlockAttributes")]
        public bool MTF_ENCRYPTION { get { return 0 != (this.BlockAttributes & (1U << 17)); } }

        byte[] bin;

        public MTF_SSET1(byte[] bin)
            : base(bin) {
            this.bin = bin;
        }
    }

    public class MTF_VOLB1 : MTF_DB_HDR {
        [Category("VOLB Header"), Browsable(false)]
        public uint VOLBAttributes { get { return BitConverter.ToUInt32(bin, 52); } }
        [Category("VOLB Header")]
        public MTF_TAPE_ADDRESS DeviceName { get { return new MTF_TAPE_ADDRESS(bin, 56); } }
        [Category("VOLB Header")]
        public MTF_TAPE_ADDRESS VolumeName { get { return new MTF_TAPE_ADDRESS(bin, 60); } }
        [Category("VOLB Header")]
        public MTF_TAPE_ADDRESS MachineName { get { return new MTF_TAPE_ADDRESS(bin, 64); } }
        [Category("VOLB Header")]
        public MTF_DATE_TIME MediaWriteDate { get { return new MTF_DATE_TIME(bin, 68); } }

        [Category("VOLB Header")]
        public string DeviceNameText { get { return Strut.GetStr(bin, 0, DeviceName, this.StringType); } }
        [Category("VOLB Header")]
        public string VolumeNameText { get { return Strut.GetStr(bin, 0, VolumeName, this.StringType); } }
        [Category("VOLB Header")]
        public string MachineNameText { get { return Strut.GetStr(bin, 0, MachineName, this.StringType); } }

        [Category("VOLBAttributes")]
        public bool VOLB_NO_REDIRECT_RESTORE_BIT { get { return 0 != (VOLBAttributes & (1U << 0)); } }
        [Category("VOLBAttributes")]
        public bool VOLB_NON_VOLUME_BIT { get { return 0 != (VOLBAttributes & (1U << 1)); } }
        [Category("VOLBAttributes")]
        public bool VOLB_DEV_DRIVE_BIT { get { return 0 != (VOLBAttributes & (1U << 2)); } }
        [Category("VOLBAttributes")]
        public bool VOLB_DEV_UNC_BIT { get { return 0 != (VOLBAttributes & (1U << 3)); } }
        [Category("VOLBAttributes")]
        public bool VOLB_DEV_OS_SPEC_BIT { get { return 0 != (VOLBAttributes & (1U << 4)); } }
        [Category("VOLBAttributes")]
        public bool VOLB_DEV_VEND_SPEC_BIT { get { return 0 != (VOLBAttributes & (1U << 5)); } }

        byte[] bin;

        public MTF_VOLB1(byte[] bin)
            : base(bin) {
            this.bin = bin;
        }
    }

    public class MTF_DIRB1 : MTF_DB_HDR {
        [Category("DIRB Header"), Browsable(false)]
        public uint DIRBAttributes { get { return BitConverter.ToUInt32(bin, 52); } }
        [Category("DIRB Header")]
        public MTF_DATE_TIME LastModificationDate { get { return new MTF_DATE_TIME(bin, 56); } }
        [Category("DIRB Header")]
        public MTF_DATE_TIME CreationDate { get { return new MTF_DATE_TIME(bin, 61); } }
        [Category("DIRB Header")]
        public MTF_DATE_TIME BackupDate { get { return new MTF_DATE_TIME(bin, 66); } }
        [Category("DIRB Header")]
        public MTF_DATE_TIME LastAccessDate { get { return new MTF_DATE_TIME(bin, 71); } }
        [Category("DIRB Header")]
        public uint DirectoryID { get { return BitConverter.ToUInt32(bin, 76); } }
        [Category("DIRB Header")]
        public MTF_TAPE_ADDRESS DirectoryName { get { return new MTF_TAPE_ADDRESS(bin, 80); } }

        [Category("DIRB Header")]
        public string DirectoryNameText { get { return Strut.GetStr(bin, 0, DirectoryName, this.StringType).Replace('\0', '\\'); } }

        [Category("DIRBAttributes")]
        public bool DIRB_READ_ONLY_BIT { get { return 0 != (DIRBAttributes & (1U << 8)); } }
        [Category("DIRBAttributes")]
        public bool DIRB_HIDDEN_BIT { get { return 0 != (DIRBAttributes & (1U << 9)); } }
        [Category("DIRBAttributes")]
        public bool DIRB_SYSTEM_BIT { get { return 0 != (DIRBAttributes & (1U << 10)); } }
        [Category("DIRBAttributes")]
        public bool DIRB_MODIFIED_BIT { get { return 0 != (DIRBAttributes & (1U << 11)); } }
        [Category("DIRBAttributes")]
        public bool DIRB_EMPTY_BIT { get { return 0 != (DIRBAttributes & (1U << 16)); } }
        [Category("DIRBAttributes")]
        public bool DIRB_PATH_IN_STREAM_BIT { get { return 0 != (DIRBAttributes & (1U << 17)); } }
        [Category("DIRBAttributes")]
        public bool DIRE_CORRUPT_BIT { get { return 0 != (DIRBAttributes & (1U << 18)); } }

        byte[] bin;

        public MTF_DIRB1(byte[] bin)
            : base(bin) {
            this.bin = bin;
        }
    }

    public class MTF_FILE1 : MTF_DB_HDR {
        [Category("FILE Header"), Browsable(false)]
        public uint FILEAttributes { get { return BitConverter.ToUInt32(bin, 52); } }
        [Category("FILE Header")]
        public MTF_DATE_TIME LastModificationDate { get { return new MTF_DATE_TIME(bin, 56); } }
        [Category("FILE Header")]
        public MTF_DATE_TIME CreationDate { get { return new MTF_DATE_TIME(bin, 61); } }
        [Category("FILE Header")]
        public MTF_DATE_TIME BackupDate { get { return new MTF_DATE_TIME(bin, 66); } }
        [Category("FILE Header")]
        public MTF_DATE_TIME LastAccessDate { get { return new MTF_DATE_TIME(bin, 71); } }
        [Category("FILE Header")]
        public uint DirectoryID { get { return BitConverter.ToUInt32(bin, 76); } }
        [Category("FILE Header")]
        public uint FileID { get { return BitConverter.ToUInt32(bin, 80); } }
        [Category("FILE Header")]
        public MTF_TAPE_ADDRESS FileName { get { return new MTF_TAPE_ADDRESS(bin, 84); } }

        [Category("FILE Header")]
        public string FileNameText { get { return Strut.GetStr(bin, 0, FileName, this.StringType); } }

        [Category("FILEAttributes")]
        public bool FILE_READ_ONLY_BIT { get { return 0 != (FILEAttributes & (1U << 8)); } }
        [Category("FILEAttributes")]
        public bool FILE_HIDDEN_BIT { get { return 0 != (FILEAttributes & (1U << 9)); } }
        [Category("FILEAttributes")]
        public bool FILE_SYSTEM_BIT { get { return 0 != (FILEAttributes & (1U << 10)); } }
        [Category("FILEAttributes")]
        public bool FILE_MODIFIED_BIT { get { return 0 != (FILEAttributes & (1U << 11)); } }
        [Category("FILEAttributes")]
        public bool FILE_IN_USE_BIT { get { return 0 != (FILEAttributes & (1U << 16)); } }
        [Category("FILEAttributes")]
        public bool FILE_NAME_IN_STREAM_BIT { get { return 0 != (FILEAttributes & (1U << 17)); } }
        [Category("FILEAttributes")]
        public bool FILE_CORRUPT_BIT { get { return 0 != (FILEAttributes & (1U << 18)); } }

        byte[] bin;

        public MTF_FILE1(byte[] bin)
            : base(bin) {
            this.bin = bin;
        }
    }

    public class MTF_EOTM1 : MTF_DB_HDR {
        [Category("EOTM Header")]
        public UInt64 LastESETPBA { get { return BitConverter.ToUInt64(bin, 52); } }

        byte[] bin;

        public MTF_EOTM1(byte[] bin)
            : base(bin) {
            this.bin = bin;
        }
    }

    public class MTF_ESET1 : MTF_DB_HDR {
        [Category("ESET Header"), Browsable(false)]
        public uint ESETAttributes { get { return BitConverter.ToUInt32(bin, 52); } }
        [Category("ESET Header")]
        public uint NumberOfCorruptFiles { get { return BitConverter.ToUInt32(bin, 56); } }
        [Category("ESET Header")]
        public ushort FDDMediaSequenceNumber { get { return BitConverter.ToUInt16(bin, 76); } }
        [Category("ESET Header")]
        public ushort DataSetNumber { get { return BitConverter.ToUInt16(bin, 78); } }
        [Category("ESET Header")]
        public MTF_DATE_TIME MediaWriteDate { get { return new MTF_DATE_TIME(bin, 80); } }

        [Category("ESETAttributes")]
        public bool ESET_Transfer_Bit { get { return 0 != (ESETAttributes & (1U << 0)); } }
        [Category("ESETAttributes")]
        public bool ESET_Copy_Bit { get { return 0 != (ESETAttributes & (1U << 1)); } }
        [Category("ESETAttributes")]
        public bool ESET_Normal_Bit { get { return 0 != (ESETAttributes & (1U << 2)); } }
        [Category("ESETAttributes")]
        public bool ESET_Differential_Bit { get { return 0 != (ESETAttributes & (1U << 3)); } }
        [Category("ESETAttributes")]
        public bool ESET_Incremental_Bit { get { return 0 != (ESETAttributes & (1U << 4)); } }
        [Category("ESETAttributes")]
        public bool ESET_Daily_Bit { get { return 0 != (ESETAttributes & (1U << 5)); } }

        byte[] bin;

        public MTF_ESET1(byte[] bin)
            : base(bin) {
            this.bin = bin;
        }
    }

    public class MTF_STREAM_HDR {
        [Category("STREAM HEADER"), Browsable(false)]
        public uint StreamID { get { return BitConverter.ToUInt32(bin, 0); } }
        [Category("STREAM HEADER"), Browsable(false)]
        public ushort StreamFileSystemAttributes { get { return BitConverter.ToUInt16(bin, 4); } }
        [Category("STREAM HEADER"), Browsable(false)]
        public ushort StreamMediaFormatAttributes { get { return BitConverter.ToUInt16(bin, 6); } }
        [Category("STREAM HEADER")]
        public ulong StreamLength { get { return BitConverter.ToUInt64(bin, 8); } }
        [Category("STREAM HEADER")]
        public ushort DataEncryptionAlgorithm { get { return BitConverter.ToUInt16(bin, 16); } }
        [Category("STREAM HEADER")]
        public ushort DataCompressionAlgorithm { get { return BitConverter.ToUInt16(bin, 18); } }
        [Category("STREAM HEADER")]
        public ushort Checksum { get { return BitConverter.ToUInt16(bin, 20); } }

        [Category("STREAM HEADER"), Description("The Stream ID is a four byte field that identifies the type of data stream.")]
        public string StreamID4CC { get { return Encoding.ASCII.GetString(bin, 0, 4); } }

        [Category("StreamFileSystemAttributes")]
        public bool STREAM_MODIFIED_BY_READ { get { return 0 != (StreamFileSystemAttributes & (1U << 0)); } }
        [Category("StreamFileSystemAttributes")]
        public bool STREAM_CONTAINS_SECURITY { get { return 0 != (StreamFileSystemAttributes & (1U << 1)); } }
        [Category("StreamFileSystemAttributes")]
        public bool STREAM_IS_NON_PORTABLE { get { return 0 != (StreamFileSystemAttributes & (1U << 2)); } }
        [Category("StreamFileSystemAttributes")]
        public bool STREAM_IS_SPARSE { get { return 0 != (StreamFileSystemAttributes & (1U << 3)); } }

        [Category("StreamMediaFormatAttributes")]
        public bool STREAM_CONTINUE { get { return 0 != (StreamMediaFormatAttributes & (1U << 0)); } }
        [Category("StreamMediaFormatAttributes")]
        public bool STREAM_VARIABLE { get { return 0 != (StreamMediaFormatAttributes & (1U << 1)); } }
        [Category("StreamMediaFormatAttributes")]
        public bool STREAM_VAR_END { get { return 0 != (StreamMediaFormatAttributes & (1U << 2)); } }
        [Category("StreamMediaFormatAttributes")]
        public bool STREAM_ENCRYPTED { get { return 0 != (StreamMediaFormatAttributes & (1U << 3)); } }
        [Category("StreamMediaFormatAttributes")]
        public bool STREAM_COMPRESSED { get { return 0 != (StreamMediaFormatAttributes & (1U << 4)); } }
        [Category("StreamMediaFormatAttributes")]
        public bool STREAM_CHECKSUMED { get { return 0 != (StreamMediaFormatAttributes & (1U << 5)); } }
        [Category("StreamMediaFormatAttributes")]
        public bool STREAM_EMBEDDED_LENGTH { get { return 0 != (StreamMediaFormatAttributes & (1U << 6)); } }

        byte[] bin;

        public MTF_STREAM_HDR(byte[] bin) {
            this.bin = bin;
        }
    }

    public class MTF_TAPE_ADDRESS {
        public ushort Size { get { return BitConverter.ToUInt16(bin, off + 0); } }
        public ushort Offset { get { return BitConverter.ToUInt16(bin, off + 2); } }

        byte[] bin;
        int off;

        public MTF_TAPE_ADDRESS(byte[] bin, int off) {
            this.bin = bin;
            this.off = off;
        }

        public override string ToString() {
            return string.Format("Offset={0}, Size={1}", Offset, Size);
        }
    }

    public class MTF_DATE_TIME {
        byte[] bin;
        int off;

        public MTF_DATE_TIME(byte[] bin, int off) {
            this.bin = bin;
            this.off = off;
        }

        public bool HasValue {
            get {
                if (bin[off + 0] != 0 || bin[off + 1] != 0 || bin[off + 2] != 0 || bin[off + 3] != 0 || bin[off + 4] != 0) {
                    try {
                        Value.ToString();
                        return true;
                    }
                    catch (ArgumentOutOfRangeException) {

                    }
                }
                return false;
            }
        }

        public DateTime Value {
            get {
                UInt64 val = (UInt64)bin[off + 0] << 32;
                val |= (UInt32)bin[off + 1] << 24;
                val |= (UInt32)bin[off + 2] << 16;
                val |= (UInt32)bin[off + 3] << 8;
                val |= (UInt32)bin[off + 4] << 0;
                return new DateTime(
                    (int)((val >> 26) & 0x3FFF),
                    (int)((val >> 22) & 0xF),
                    (int)((val >> 17) & 0x1F),
                    (int)((val >> 12) & 0x1F),
                    (int)((val >> 6) & 0x3F),
                    (int)((val >> 0) & 0x3F)
                    );
            }
        }

        public override string ToString() {
            return HasValue ? Value.ToString("yyyy/MM/dd HH:mm:ss") : "";
        }
    }

    class BUt {
        public static byte[] Cut(byte[] bin, int off, int size) {
            byte[] cutbin = new byte[size];
            for (int x = 0; x < size; x++) cutbin[x] = bin[off + x];
            return cutbin;
        }
    }
}
